Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EuiColorStops: Feature Stepped ColorStops #4613

Merged
merged 20 commits into from
Mar 31, 2021

Conversation

anuragxxd
Copy link
Contributor

@anuragxxd anuragxxd commented Mar 5, 2021

Summary

This is to add the new feature to the euiColorStops:- Closes #4570

Checklist

  • Check against all themes for compatibility in both light and dark modes
  • Checked in mobile
  • Checked in Chrome, Safari, Edge, and Firefox
  • Props have proper autodocs and playground toggles
  • Added documentation
  • Checked Code Sandbox works for the any docs examples
  • Added or updated jest tests
  • Checked for breaking changes and labeled appropriately
  • Checked for accessibility including keyboard-only and screenreader modes
  • A changelog entry exists and is marked appropriately

@kibanamachine
Copy link

Since this is a community submitted pull request, a Jenkins build has not been kicked off automatically. Can an Elastic organization member please verify the contents of this patch and then kick off a build manually?

@anuragxxd anuragxxd marked this pull request as ready for review March 5, 2021 13:42
@anuragxxd
Copy link
Contributor Author

This is all done to merge please review this @flash1293 @cchaos.
Will have to do some changes in the examples for that this pr need to be merged. Once Done I will make final changes and changelog entry.

@thompsongl thompsongl self-requested a review March 5, 2021 13:45
@thompsongl
Copy link
Contributor

Hey @git-anurag-hub,

Thanks for getting this started! We'll need to make some changes before this is ready to merge.

A couple comments to start:

All changes should be scoped to color_stops files. That is, range_highlight should have no knowledge that a "stepped" option exists. At most, the background prop in range_highlight could be modified to accept multiple background definitions.
So, all stepped background logic should be handled in the same manner and location as the "fixed" and "gradient" options. Aligning the "stepped" gradient creation to the pattern(s) established by "fixed" and "gradient" will be helpful in creating a a background that fits the location of the stop handles.

Also, we'll need to account for custom min-max domains. That is, we cannot assume that the scale will always be from 0-1 or 0-100. Just important to keep in mind for calculations.

@anuragxxd
Copy link
Contributor Author

Okay will commit changes once I am done with these. 👍
Thanks for help.

@anuragxxd
Copy link
Contributor Author

anuragxxd commented Mar 5, 2021

@thompsongl It will not be possible to remove the stepped from the range_highlight as making the styles for the fixed or gradient & stepped it totally different but I can do one thing to remove it i.e. I can instead of passing the colors as the prop I can send the background styles directly from the parent component.
Also if in future if range_highlight component is used I will set some default background styles. Is this okay.
If not. Any suggestion from your end are most welcomed. :)

@thompsongl
Copy link
Contributor

It will not be possible to remove the stepped from the range_highlight as making the styles for the fixed or gradient & stepped it totally different

It is possible to create a stepped linear gradient in the same manner as the other gradient types; see an example here: https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient()#gradient_with_multi-position_color_stops
A linear gradient like this can be passed to the same background prop as the other gradient types. This will allow all logic to create the stepped gradient to be moved from range_highlight to color_stops. The stepped prop should also then be removed from range_highlight.

Also if in future if range_highlight component is used

The reason that color_stops logic should not be part of range_highlight is that it is already being used in other components, namely EuiRange and EuiDualRange. We want to avoid further changes to this component, especially when its current props are sufficient for the new use case (i.e., background prop).

@anuragxxd
Copy link
Contributor Author

Made changes @thompsongl @flash1293.

Copy link
Contributor

@flash1293 flash1293 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works pretty well already! Left some small comments.

About the behavior - all other palettes start at the first stop, except for stepped color segments. I think it should behave in the same way and use the default gray color for the area from start to first stop, just to keep consistency:
Screenshot 2021-03-09 at 11 50 41

@anuragxxd
Copy link
Contributor Author

Also @flash1293 @thompsongl where is the default grey colour stored maybe in some variable name of something. I am not able to find it.

@anuragxxd anuragxxd requested a review from flash1293 March 9, 2021 11:59
@thompsongl
Copy link
Contributor

About the behavior - all other palettes start at the first stop, except for stepped color segments. I think it should behave in the same way and use the default gray color for the area from start to first stop, just to keep consistency

Yes, I agree this is how it should work.

where is the default grey colour stored maybe in some variable name of something. I am not able to find it.

Use currentColor, which is a CSS feature that will use the current text color (which we've set to gray). See the other gradient examples for how it's used: https://github.com/elastic/eui/blob/master/src/components/color_picker/color_stops/color_stops.tsx#L429

@anuragxxd
Copy link
Contributor Author

If we provide the color as currentColor chroma shows the error.
@thompsongl
Screenshot 2021-03-09 at 9 47 28 PM

Screenshot 2021-03-09 at 9 47 08 PM

@flash1293
Copy link
Contributor

@git-anurag-hub Don't pass currentColor to chroma, it's a css thing. You have to do this in the place where you build the actual css background string in the component (src/components/color_picker/color_stops/color_stops.tsx)

@anuragxxd
Copy link
Contributor Author

anuragxxd commented Mar 9, 2021

We can't do that because we have to make the stepped background first before providing it to the css.
It is done in the linear gradient because we have to provide it directly to the css before providing it to the anything else.

@thompsongl One thing I can do is provide the hex value of the grey color you are using but I don't think it is the great idea/solution.

@flash1293
Copy link
Contributor

@git-anurag-hub Then you have to refactor your code - the helper function in util shouldn't care about the currentColor thing in the beginning, it has to be added afterwards before building the css gradient

@anuragxxd
Copy link
Contributor Author

anuragxxd commented Mar 9, 2021

We can't do this because we are using chromajs to make the steps and we need to provide the first color (i.e. grey). @flash1293 @thompsongl

@flash1293
Copy link
Contributor

flash1293 commented Mar 9, 2021

@git-anurag-hub This is how it should work:

It might be just because you didn't push your current state, but you resolved some comments without changing anything.

@thompsongl
Copy link
Contributor

@flash1293 is exactly right. You can think of the gray color before the first stop as an 'empty' space; it has not been configured with a color by the user. For that reason, currentColor should not be included as one of the 10 (by default) color steps in the gradient.
So if the first color stop is 'red' at '20', currentColor occupies the space from 0-20 and does not need to be included in the chroma function to create the stepped color gradient from 20-100.

Let me know if this makes sense, and thanks for sticking with us as we provide feedback; your help is much appreciated

@anuragxxd
Copy link
Contributor Author

anuragxxd commented Mar 9, 2021

Np @flash1293 @thompsongl Can please review pr once again as I made the changes asked for.
It will be great if you can please review this today so that I can work on something else tomorrow. :)

Copy link
Contributor

@flash1293 flash1293 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I played around with the picker and the colors behave a little weird:

Two stops, three steps - it looks like I would expect. The first segment takes the first color, the last one takes the last color, the one in the middle takes an interpolated color
Screenshot 2021-03-10 at 15 30 27

But if I drag the first stop to the right, the middle segment turns into the first color until there are only two segments visible:
Screenshot 2021-03-10 at 15 30 32

Do you know why that happens? The segments do get smaller while I'm dragging, so it doesn't make sense for the middle segment to change color.

@@ -45,6 +49,8 @@ import { EuiScreenReaderOnly } from '../../accessibility';
import { EuiRangeHighlight } from '../../form/range/range_highlight';
import { EuiRangeTrack } from '../../form/range/range_track';
import { EuiRangeWrapper } from '../../form/range/range_wrapper';
// import { colorPalette } from '../../../services/color/color_palette';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused imports, please remove

colors: ColorStop[],
steps: number
) {
const finalStops = [0, ...colors.map((item) => item.stop / 100), 1];
Copy link
Contributor

@flash1293 flash1293 Mar 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@git-anurag-hub This logic always assumes a min of 0 and a max of 100, but that's not the case - the user can configure min and max. This logic needs to be aware. As far as I can tell that's also the reason for the behavior described here: #4613 (review)

The color segments should be done between the first and last stop

@thompsongl
Copy link
Contributor

Thanks, @flash1293

This is looking good so far! A couple things I noticed while clicking around the demo:

image

It's possible to get into odd configurations where a colors appears before the drag handle of the previous color (e.g., pink before the yellow handle).

image

Low step counts have the potential to misrepresent the color distribution. Also, should we add a rule to force the step count to be at least equal to the number of drag handles (i.e., minimum of 3 in the above screenshot)?

Given your explanation that the stepped gradient is "actually just a quantization postprocessing of the smoothly interpolated palette", both of these seem to be acceptable/expected, but what to get your thoughts.


Regarding the onChange value, no information is returned to the consumer about the stepped gradient. Like the other gradient types, you simply get the drag handle values:

[
  {stop: 20, color: "#54B399"},
  {stop: 50, color: "#D36086"},
  {stop: 64, color: "#9170B8"}
]

As a consumer, do you need access to the values and start/stop locations of each gradient step?

@flash1293
Copy link
Contributor

Thanks for the check @thompsongl

It's possible to get into odd configurations where a colors appears before the drag handle of the previous color (e.g., pink before the yellow handle).

Yes, this is due to the way the palette is quantized - it's not taking the center of each segments for the color. The first segment is colored by the very first step, the last segment by the very last step, and the places to use color from in between are evenly distributed. This only matches with the center of the segment for the middle segment. This shows from where on the spectrum the individual segments get their color:
112524805-3c266400-8d6e-11eb-9d26-44b577140384

I thought back and forth on this - another thing we could do is this:
112524805-3c266400-8d6e-11eb-9d26-44b577140384

But it has other weird edge cases - now there won't be a segment colored exactly like the beginning and end colors, but always a blend - in the example above the first segment would be a blend of green and yellow, the second segment would be a green/yellow blend with less green, and the last one would be perfect yellow with no red at all - which is also weird IMHO.

I thought we can start with this and if people complain we can introduce more options - as you mentioned this is an edge case anyway.

Low step counts have the potential to misrepresent the color distribution. Also, should we add a rule to force the step count to be at least equal to the number of drag handles (i.e., minimum of 3 in the above screenshot)?

Good point, I think we can enforce this on the consumers side, but I would keep the component itself unbiased.

As a consumer, do you need access to the values and start/stop locations of each gradient step?

No, that's fine as they will be evenly distributed. As we will have some logic for this on the consumer side anyway, I think the current abstraction level is fine.

@thompsongl
Copy link
Contributor

I thought we can start with this and if people complain we can introduce more options - as you mentioned this is an edge case anyway.

This makes sense to me. The core API is settled, especially if we don't enforce restrictions on step count. Any future changes would likely be visual in nature or add new options. I'll take another review of the code.

jenkins test this

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4613/

@cchaos cchaos requested a review from elizabetdev March 29, 2021 17:00
@thompsongl
Copy link
Contributor

Snapshot test failure:

09:37:16             <div
09:37:16               class="euiRangeHighlight__progress"
09:37:16     -         style="background:linear-gradient(to right, currentColor 0%, #ff0000 0% 3.5%, #d72800 3.5% 7%, #b04f00 7% 10.5%, #887700 10.5% 14%, #609f00 14% 17.5%, #39c600 17.5% 21%, #11ee00 21% 24.5%, #00c639 24.5% 28%, #00639c 28% 31.5%, #0000ff 31.5% 35%);margin-left:0%;width:100%"
09:37:16     +         style="background:linear-gradient(to right, currentColor undefined%, #ff0000 NaN% NaN%, #d72800 NaN% NaN%, #b04f00 NaN% NaN%, #887700 NaN% NaN%, #609f00 NaN% NaN%, #39c600 NaN% NaN%, #11ee00 NaN% NaN%, #00c639 NaN% NaN%, #00639c NaN% NaN%, #0000ff NaN% NaN%);margin-left:0%;width:100%"
09:37:16             />

@flash1293
Copy link
Contributor

Jenkins, test this

@flash1293
Copy link
Contributor

@thompsongl Fixed the failing test. As I rely on the positions array now which requires a dom measurement, I changed how the test works.

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4613/

@flash1293
Copy link
Contributor

Jenkins, test this

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4613/

Copy link
Contributor

@elizabetdev elizabetdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @git-anurag-hub,

Tested in Chrome, Safari, Edge and Firefox, and LGTM! 🎉

I did a review more focused on the design aspects of the PR, and I moved the steps into a popover to match other examples.

steps@2x

I also added a few prop descriptions.

Screenshot 2021-03-30 at 13 34 27

* Specify the type of stops:
* `fixed`: individual color blocks.
* `gradient`: each color fades into the next.
* `stepped`: interpolation between colors with a fixed number of steps.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added an explanation for each stopType. Not sure if this is the best explanation for what the stepped option does. A better suggestion is welcome. 😄

Co-authored-by: Elizabet Oliveira <[email protected]>
@flash1293
Copy link
Contributor

Jenkins, test this

@flash1293
Copy link
Contributor

Thanks @miukimiu !

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4613/

Copy link
Contributor

@thompsongl thompsongl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after the one change below
Thanks @git-anurag-hub for getting this started
Thanks @flash1293 for getting it across the finish line
Thanks @miukimiu for the docs improvements

@flash1293
Copy link
Contributor

Jenkins, test this

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_4613/

@flash1293 flash1293 merged commit e05b86a into elastic:master Mar 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[EuiColorStops] Allow stepped colors between stops
5 participants